package org.hhf.transaction;

import org.hhf.core.RedisCore;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * TransactionRedis类实现了Redis的事务功能
 */
public class TransactionRedis {
    private final RedisCore core;
    // 存储每个客户端的事务队列
    private final ConcurrentHashMap<String, TransactionState> transactions = new ConcurrentHashMap<>();
    
    public TransactionRedis(RedisCore core) {
        this.core = core;
    }
    
    /**
     * 事务状态类
     */
    public static class TransactionState {
        private final List<QueuedCommand> commandQueue = new ArrayList<>();
        private final Set<String> watchedKeys = new HashSet<>();
        private final Map<String, Object> watchedValues = new HashMap<>();
        private boolean isMultiMode = false;
        private boolean isWatchInvalid = false;
        
        public List<QueuedCommand> getCommandQueue() {
            return commandQueue;
        }
        
        public Set<String> getWatchedKeys() {
            return watchedKeys;
        }
        
        public Map<String, Object> getWatchedValues() {
            return watchedValues;
        }
        
        public boolean isMultiMode() {
            return isMultiMode;
        }
        
        public void setMultiMode(boolean multiMode) {
            isMultiMode = multiMode;
        }
        
        public boolean isWatchInvalid() {
            return isWatchInvalid;
        }
        
        public void setWatchInvalid(boolean watchInvalid) {
            isWatchInvalid = watchInvalid;
        }
    }
    
    /**
     * 队列命令类
     */
    public static class QueuedCommand {
        private final String command;
        private final String[] args;
        
        public QueuedCommand(String command, String[] args) {
            this.command = command;
            this.args = args;
        }
        
        public String getCommand() {
            return command;
        }
        
        public String[] getArgs() {
            return args;
        }
    }
    
    /**
     * 开始事务
     */
    public String multi(String clientId) {
        TransactionState state = getOrCreateTransaction(clientId);
        state.setMultiMode(true);
        state.getCommandQueue().clear();
        return "OK";
    }
    
    /**
     * 执行事务
     */
    public List<Object> exec(String clientId) {
        TransactionState state = transactions.get(clientId);
        if (state == null || !state.isMultiMode()) {
            return null; // 没有开始事务
        }
        
        List<Object> results = new ArrayList<>();
        
        // 检查watched keys是否被修改
        if (state.isWatchInvalid() || isWatchedKeysModified(state)) {
            // 事务被打断，返回null
            state.setMultiMode(false);
            state.getCommandQueue().clear();
            state.getWatchedKeys().clear();
            state.getWatchedValues().clear();
            return null;
        }
        
        // 执行队列中的所有命令
        for (QueuedCommand queuedCommand : state.getCommandQueue()) {
            try {
                // 这里需要调用CommandProcessor来执行命令
                // 为了简化，我们返回一个占位符结果
                results.add("QUEUED");
            } catch (Exception e) {
                results.add("-ERR " + e.getMessage());
            }
        }
        
        // 清理事务状态
        state.setMultiMode(false);
        state.getCommandQueue().clear();
        state.getWatchedKeys().clear();
        state.getWatchedValues().clear();
        
        return results;
    }
    
    /**
     * 取消事务
     */
    public String discard(String clientId) {
        TransactionState state = transactions.get(clientId);
        if (state == null || !state.isMultiMode()) {
            return "-ERR DISCARD without MULTI";
        }
        
        state.setMultiMode(false);
        state.getCommandQueue().clear();
        return "OK";
    }
    
    /**
     * 监视键
     */
    public String watch(String clientId, String... keys) {
        TransactionState state = getOrCreateTransaction(clientId);
        
        for (String key : keys) {
            state.getWatchedKeys().add(key);
            state.getWatchedValues().put(key, core.get(key));
        }
        
        return "OK";
    }
    
    /**
     * 取消监视所有键
     */
    public String unwatch(String clientId) {
        TransactionState state = transactions.get(clientId);
        if (state != null) {
            state.getWatchedKeys().clear();
            state.getWatchedValues().clear();
            state.setWatchInvalid(false);
        }
        return "OK";
    }
    
    /**
     * 将命令加入队列
     */
    public String queueCommand(String clientId, String command, String[] args) {
        TransactionState state = transactions.get(clientId);
        if (state == null || !state.isMultiMode()) {
            return null; // 不在事务模式中
        }
        
        state.getCommandQueue().add(new QueuedCommand(command, args));
        return "QUEUED";
    }
    
    /**
     * 检查客户端是否在事务模式中
     */
    public boolean isInTransaction(String clientId) {
        TransactionState state = transactions.get(clientId);
        return state != null && state.isMultiMode();
    }
    
    /**
     * 标记watched keys为无效（当键被修改时调用）
     */
    public void invalidateWatchedKeys(String key) {
        for (TransactionState state : transactions.values()) {
            if (state.getWatchedKeys().contains(key)) {
                state.setWatchInvalid(true);
            }
        }
    }
    
    /**
     * 获取或创建事务状态
     */
    private TransactionState getOrCreateTransaction(String clientId) {
        return transactions.computeIfAbsent(clientId, k -> new TransactionState());
    }
    
    /**
     * 检查watched keys是否被修改
     */
    private boolean isWatchedKeysModified(TransactionState state) {
        for (String key : state.getWatchedKeys()) {
            Object currentValue = core.get(key);
            Object watchedValue = state.getWatchedValues().get(key);
            
            if (!Objects.equals(currentValue, watchedValue)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * 清理客户端的事务状态
     */
    public void cleanupClient(String clientId) {
        transactions.remove(clientId);
    }
}